package com.lcy.pay.controller;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.io.IOUtils;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.HttpClients;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.domain.AlipayTradeQueryModel;
import com.alipay.api.domain.AlipayTradeWapPayModel;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.AlipayTradeQueryRequest;
import com.alipay.api.request.AlipayTradeWapPayRequest;
import com.alipay.api.response.AlipayTradeQueryResponse;
import com.lcy.pay.config.AlipayConfig;
import com.lcy.pay.config.WxpayConfig;

@Controller
@RequestMapping("")
public class PayController {

	private final static Logger logger = LoggerFactory.getLogger(PayController.class);

	/**
	 * 微信回调接口
	 *
	 * @param request
	 * @param response
	 * @throws AlipayApiException
	 * @throws IOException
	 */
	@RequestMapping("/notify-weixin")
	@ResponseBody
	public String notifyWX(HttpServletRequest request, HttpServletResponse response)
			throws AlipayApiException, IOException {
		String responseStr = "";
		try {
			responseStr = IOUtils.toString(request.getInputStream(), "utf-8");
		} catch (IOException e) {
			logger.error("", e);
		}
		logger.info("weixin notify:" + responseStr);
		return null;
	}

	/**
	 * 支付宝回调接口
	 *
	 * @param request
	 * @param response
	 * @throws AlipayApiException
	 * @throws IOException
	 */
	@RequestMapping("/notify-zfb")
	@ResponseBody
	public String notifyZFB(HttpServletRequest request, HttpServletResponse response)
			throws AlipayApiException, IOException {
		// 获取支付宝POST过来反馈信息
		Map<String, String> params = new HashMap<String, String>();
		Map<String, String[]> requestParams = request.getParameterMap();
		for (Iterator<String> iter = requestParams.keySet().iterator(); iter.hasNext();) {
			String name = iter.next();
			String[] values = requestParams.get(name);
			String valueStr = "";
			for (int i = 0; i < values.length; i++) {
				valueStr = (i == (values.length - 1)) ? valueStr + values[i] : valueStr + values[i] + ",";
			}
			// 乱码解决，这段代码在出现乱码时使用。如果mysign和sign不相等也可以使用这段代码转化
			// valueStr = new String(valueStr.getBytes("ISO-8859-1"), "gbk");
			params.put(name, valueStr);
		}
		// 获取支付宝的通知返回参数，可参考技术文档中页面跳转同步通知参数列表(以下仅供参考)//
		// 商户订单号
		String out_trade_no = new String(request.getParameter("out_trade_no").getBytes("ISO-8859-1"), "UTF-8");
		System.out.println("交易订单：" + out_trade_no + "回调成功");
		// 支付宝交易号
		String trade_no = new String(request.getParameter("trade_no").getBytes("ISO-8859-1"), "UTF-8");
		System.out.println("交易订单：" + trade_no + "回调成功");

		// 交易状态
		String trade_status = new String(request.getParameter("trade_status").getBytes("ISO-8859-1"), "UTF-8");

		// 获取支付宝的通知返回参数，可参考技术文档中页面跳转同步通知参数列表(以上仅供参考)//
		// 计算得出通知验证结果
		// boolean AlipaySignature.rsaCheckV1(Map<String, String> params, String
		// publicKey, String charset, String sign_type)
		boolean verify_result = AlipaySignature.rsaCheckV1(params, AlipayConfig.ALIPAY_PUBLIC_KEY, AlipayConfig.CHARSET,
				AlipayConfig.SIGNTYPE);

		if (verify_result) {// 验证成功
			//////////////////////////////////////////////////////////////////////////////////////////
			// 请在这里加上商户的业务逻辑程序代码

			// ——请根据您的业务逻辑来编写程序（以下代码仅作参考）——

			if (trade_status.equals("TRADE_FINISHED")) {
				// 判断该笔订单是否在商户网站中已经做过处理
				// 如果没有做过处理，根据订单号（out_trade_no）在商户网站的订单系统中查到该笔订单的详细，并执行商户的业务程序
				// 请务必判断请求时的total_fee、seller_id与通知时获取的total_fee、seller_id为一致的
				// 如果有做过处理，不执行商户的业务程序

				// 注意：
				// 如果签约的是可退款协议，退款日期超过可退款期限后（如三个月可退款），支付宝系统发送该交易状态通知
				// 如果没有签约可退款协议，那么付款完成后，支付宝系统发送该交易状态通知。
			} else if (trade_status.equals("TRADE_SUCCESS")) {
				// 判断该笔订单是否在商户网站中已经做过处理
				// 如果没有做过处理，根据订单号（out_trade_no）在商户网站的订单系统中查到该笔订单的详细，并执行商户的业务程序
				// 请务必判断请求时的total_fee、seller_id与通知时获取的total_fee、seller_id为一致的
				// 如果有做过处理，不执行商户的业务程序

				// 注意：
				// 如果签约的是可退款协议，那么付款完成后，支付宝系统发送该交易状态通知。
			}

			// ——请根据您的业务逻辑来编写程序（以上代码仅作参考）——
			return "success"; // 请不要修改或删除

			//////////////////////////////////////////////////////////////////////////////////////////
		} else {// 验证失败
			return "fail";
		}
	}

	/**
	 * 支付成功返回页面
	 */
	@RequestMapping(value = "/success")
	public String paySuccess() {
		return "pay-success";
	}

	public String gotoZFBPay(HttpServletRequest request, HttpServletResponse response, String money) {
		// 商户订单号，商户网站订单系统中唯一订单号，必填
		String out_trade_no = "17071715214970702";
		System.out.println("生成订单：" + out_trade_no);
		// 订单名称，必填
		String subject = "这是测试订单";
		// 付款金额，必填
		String total_amount = "10";
		// 商品描述，可空
		String body = "这是测试的商品body";
		// 超时时间 可空
		String timeout_express = "2m";
		// 销售产品码 必填
		String product_code = "QUICK_WAP_PAY";
		/**********************/
		// SDK 公共请求类，包含公共请求参数，以及封装了签名与验签，开发者无需关注签名与验签
		// 调用RSA签名方式
		AlipayClient client = new DefaultAlipayClient(AlipayConfig.URL, AlipayConfig.APPID,
				AlipayConfig.RSA_PRIVATE_KEY, AlipayConfig.FORMAT, AlipayConfig.CHARSET, AlipayConfig.ALIPAY_PUBLIC_KEY,
				AlipayConfig.SIGNTYPE);
		AlipayTradeWapPayRequest alipay_request = new AlipayTradeWapPayRequest();

		// 封装请求支付信息
		AlipayTradeWapPayModel model = new AlipayTradeWapPayModel();
		model.setOutTradeNo(out_trade_no);
		model.setSubject(subject);
		model.setTotalAmount(total_amount);
		model.setBody(body);
		model.setTimeoutExpress(timeout_express);
		model.setProductCode(product_code);
		alipay_request.setBizModel(model);
		// 设置异步通知地址
		alipay_request.setNotifyUrl(AlipayConfig.notify_url);
		// 设置同步地址
		alipay_request.setReturnUrl(AlipayConfig.return_url);

		// form表单生产
		String form = "";
		try {
			// 调用SDK生成表单
			form = client.pageExecute(alipay_request).getBody();
			response.setContentType("text/html;charset=" + AlipayConfig.CHARSET);
			return form;// 直接将完整的表单html输出到页面
		} catch (AlipayApiException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return form;
	}

	/**
	 * 支付下单接口
	 *
	 * @param request
	 * @param response
	 */
	@RequestMapping("/gotoPay")
	@ResponseBody
	public String gotoPay(HttpServletRequest request, HttpServletResponse response, @RequestParam("money") String money,
			@RequestParam("payWay") String payWay) {

		if ("zhifubao".equals(payWay)) {
			return this.gotoZFBPay(request, response, money);
		} else if ("weixin".equals(payWay)) {
			return this.gotoWeixinPay(request, Long.valueOf(money));
		}
		return null;
	}

	public String getIp(HttpServletRequest request) {
		String ip = request.getHeader("X-Forwarded-For");
		if (!StringUtils.isEmpty(ip) && !"unKnown".equalsIgnoreCase(ip)) {
			// 多次反向代理后会有多个ip值，第一个ip才是真实ip
			int index = ip.indexOf(",");
			if (index != -1) {
				return ip.substring(0, index);
			} else {
				return ip;
			}
		}
		ip = request.getHeader("X-Real-IP");
		if (!StringUtils.isEmpty(ip) && !"unKnown".equalsIgnoreCase(ip)) {
			return ip;
		}
		return request.getRemoteAddr();
	}

	/**
	 * 微信支付
	 *
	 * @param request
	 * @param response
	 * @param money
	 * @return
	 */
	private String gotoWeixinPay(HttpServletRequest request, long money) {

		long limit = money * 100;
		SimpleDateFormat sdf = new SimpleDateFormat("yyMMddHHmmss");
		String oderNo = sdf.format(new Date());
		String nonceStr = System.currentTimeMillis() + limit + oderNo;
		String nonce_str = "";
		try {
			nonce_str = DigestUtils.md5Hex(nonceStr.getBytes("utf8"));
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
		String spbill_create_ip = this.getIp(request);

		String attach = "";

		StringBuffer signStr = new StringBuffer();
		signStr.append("appid=" + WxpayConfig.APPID + "&");
		signStr.append("attach=" + attach + "&");
		signStr.append("body=神游客" + "&");
		signStr.append("mch_id=" + WxpayConfig.MCH_ID + "&");
		signStr.append("nonce_str=" + nonce_str + "&");
		signStr.append("notify_url=" + WxpayConfig.NOTIFY_URL + "&");
		signStr.append("out_trade_no=" + oderNo + "&");
		signStr.append("spbill_create_ip=" + spbill_create_ip + "&");
		signStr.append("total_fee=" + limit + "&");
		signStr.append("trade_type=" + WxpayConfig.TRADE_TYPE + "&");
		logger.debug(" Sign str \n {} " + signStr.toString());
		String sign = DigestUtils.md5Hex(signStr.toString()).toUpperCase();
		logger.debug(" sign = {} " + sign);
		// 生成提交参数
		StringBuffer xmlBuffer = new StringBuffer("<xml>");
		xmlBuffer.append("\n\t<appid>" + WxpayConfig.APPID + "</appid>");
		xmlBuffer.append("\n\t<attach>" + attach + "</attach>");
		xmlBuffer.append("\n\t<body>" + "神游客" + "</body>");
		xmlBuffer.append("\n\t<mch_id>" + WxpayConfig.MCH_ID + "</mch_id>");
		xmlBuffer.append("\n\t<nonce_str>" + nonce_str + "</nonce_str>");
		xmlBuffer.append("\n\t<notify_url>" + WxpayConfig.NOTIFY_URL + "</notify_url>");
		xmlBuffer.append("\n\t<out_trade_no>" + oderNo + "</out_trade_no>");
		xmlBuffer.append("\n\t<spbill_create_ip>" + spbill_create_ip + "</spbill_create_ip>");
		xmlBuffer.append("\n\t<total_fee>" + limit + "</total_fee>");
		xmlBuffer.append("\n\t<trade_type>" + WxpayConfig.TRADE_TYPE + "</trade_type>");
		xmlBuffer.append("\n\t<sign>" + sign + "</sign>");
		xmlBuffer.append("\n</xml>");

		HttpPost httpPost = new HttpPost(WxpayConfig.URL_ADDORDER_H5);

		try {
			httpPost.setEntity(new StringEntity(xmlBuffer.toString(), "utf-8"));
			httpPost.setHeader("User-Agent", "Mozilla/5.0");
			HttpClient httpClient = HttpClients.createDefault();
			HttpResponse response = httpClient.execute(httpPost);

			String responseStr = IOUtils.toString(response.getEntity().getContent(), "utf-8");
			logger.info("WxPay response :" + responseStr);
			// TODO 根据微信返回数据做相应处理，返回前端跳转的url地址
			return responseStr;
		} catch (UnsupportedEncodingException e) {
			throw new RuntimeException(e);
		} catch (IOException e) {
			throw new RuntimeException(e);
		}
	}

	/**
	 * 订单查询接口
	 *
	 * @param request
	 * @param response
	 * @return
	 * @throws UnsupportedEncodingException
	 * @throws AlipayApiException
	 */
	public String queryOrder(HttpServletRequest request, HttpServletResponse response)
			throws UnsupportedEncodingException, AlipayApiException {
		String out_trade_no = new String(request.getParameter("WIDout_trade_no").getBytes("ISO-8859-1"), "UTF-8");
		// 支付宝交易号
		String trade_no = new String(request.getParameter("WIDtrade_no").getBytes("ISO-8859-1"), "UTF-8");
		/**********************/
		AlipayTradeQueryResponse alipay_response = this.queryOrder(out_trade_no, trade_no);
		return null;
	}

	/**
	 *
	 * @param out_trade_no
	 *            平台订单号
	 * @param trade_no
	 *            支付宝平台订单号
	 * @return
	 * @throws AlipayApiException
	 */
	private AlipayTradeQueryResponse queryOrder(String out_trade_no, String trade_no) throws AlipayApiException {
		// SDK 公共请求类，包含公共请求参数，以及封装了签名与验签，开发者无需关注签名与验签
		AlipayClient client = new DefaultAlipayClient(AlipayConfig.URL, AlipayConfig.APPID,
				AlipayConfig.RSA_PRIVATE_KEY, AlipayConfig.FORMAT, AlipayConfig.CHARSET, AlipayConfig.ALIPAY_PUBLIC_KEY,
				AlipayConfig.SIGNTYPE);
		AlipayTradeQueryRequest alipay_request = new AlipayTradeQueryRequest();

		AlipayTradeQueryModel model = new AlipayTradeQueryModel();
		model.setOutTradeNo(out_trade_no);
		model.setTradeNo(trade_no);
		alipay_request.setBizModel(model);

		AlipayTradeQueryResponse alipay_response = client.execute(alipay_request);
		System.out.println(alipay_response.getBody());
		return alipay_response;
	}
}
